﻿#pragma once

#include <occmesh/api/utils.h>

enum class FillingType
{
    G0,
    G1
};

struct FillingParamData
{
    int maxIter{8};
    int maxSampleNum{2000};
    int uDegree{5}, vDegree{5};
    int uControlNum{6}, vControlNum{6}, insertNum{3};
    double weightStretching{1 * 1e-3};
    double weightBending{3 * 1e-1};
    double weightRocinBending{7 * 1e-1};
    // 注意比例尺，小尺寸物件不使用 1e-3 放缩
    double weightG0{0.6};
    double weightG1{0.4};
    double parameterFieldAdd{0.1};
    double maxG0{1e-3};
    double maxG1{0.05};
};

struct FillingBoundaryData
{
    std::vector<Handle(Geom_Surface)> boundarySurfaces;        // 边界曲面
    std::vector<Handle(Geom_Curve)> boundaryCurves;            // 边界曲线
    std::vector<Handle(Geom2d_Curve)> boundary2dCurves;        // p-curves
    std::vector<FillingType> boundaryTypes;                    // 边界条件
    std::vector<std::tuple<double, double>> curveParamsRanges; // 边界曲线参数范围
    std::vector<double> boundarySampleParams;                  // 边界采样参数
    std::vector<int> boundarySampleNums;                       // 边界采样参数
    std::vector<gp_Pnt2d> uvParams;                            // 边界采样点在参数域上的投影
    std::vector<gp_Pnt> samplePoints;                          // 边界采样点
};

struct FillingIntegralData
{
    std::vector<std::vector<gp_Vec>> integralNormals;                           // 采样积分节点法向
    std::vector<std::vector<std::tuple<double, double, double>>> integralNodes; // 采样积分节点
};

struct FillingResultData
{
    double umin, umax, vmin, vmax;       // 参数域范围
    std::vector<double> uKnots, vKnots;  // 节点向量
    Handle(Geom_BSplineSurface) surface; // 补洞曲面
    Handle(Geom_BSplineSurface) best;    // 最佳曲面
};

// 补洞算法
struct FillingBuilder
{
  private:
    FillingParamData m_paramData;
    FillingBoundaryData m_boundaryData;
    FillingIntegralData m_integralData;
    FillingResultData m_resultData;

  public:
    FillingBuilder(const std::vector<std::tuple<TopoDS_Edge, TopoDS_Face>> &mapList);

    // 根据参数生成补洞曲面
    TopoDS_Face Build(const FillingParamData &paramData);

  private:
    void SampleAndParameterize();
    void ConstructPCurves();
    void ConstructIntegralCurves();
    void UpdateInitialSurface();
    void ConstructOptimizedSystem();
    void Reparameterize();
    void ModifyWeights();
    void ConstructTrimmedSurface();
};
